`timescale 1ns / 1ps
`include "defines.vh"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/10 19:01:53
// Design Name: 
// Module Name: CU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


// CU接收ID解析后的部分译码信息，执行，取出写入，计算操作
module CU (
    input [0:0] clk,
    input [0:0] rst,


    //从ID接收
    input [`Instruction_Bus] Instruction_Input,  //指令内容
    input [`Instruction_Addr_Bus] Instruction_Addr_Input,

    input [6:0] opcode,  //操作码
    input [11:0] imm12,  //12位立即数
    input [19:0] imm20,  //20位立即数
    input [0:0] dis,  //区分码
    input [2:0] func3,  //func3
    input [6:0] func7,  //func7



    input [0:0] Write_Reg_Flag,  //寄存器写标志
    input [`Reg_Addr_Bus] Write_Reg_Addr,  //寄存器写地址

    //发送到ALU
    output reg [`ALU_Operation_BUS] ALU_Operation = `ALU_Rst_Operation,
    output reg [`ALU_Parameter_BUS] ALU_A_Output = `ALU_Rst_Data,
    output reg [`ALU_Parameter_BUS] ALU_B_Output = `ALU_Rst_Data,


    // 从Regs接收
    input [`Reg_Data_Bus] Reg_1_Read_Data_Input,  // 寄存器1数据
    input [`Reg_Data_Bus] Reg_2_Read_Data_Input,  // 寄存器2数据   


    // 发送到 EX_MEM_WB_Regs //必须等到ALU给出结果后开始写   //-//
    output reg [0:0] Write_Reg_Flag_Output,  //寄存器写标志
    output reg [`Reg_Addr_Bus] Write_Reg_Addr_Output,  //寄存器写地址

    output reg [0:0] RAM_Access_Flag_Output,  //内存访问标志
    output reg [`RAM_Operation_BUS] RAM_Operation_Output,  //内存操作数
    output reg [`RAM_Data_BUS] RAM_Write_Data_Output,  //内存写数据

    output reg[0:0] Write_Reg_from_ALU_Flag_Output, //寄存器写数据由ALU得到 标志
    output reg[0:0] Write_Reg_from_CU_Flag_Output, //寄存器写入值由CU得到 标志
    output reg [`Reg_Data_Bus] Write_Reg_from_CU_Data_Output,

    // 与最顶层交互
    input [`Reg_Data_Bus] Input_Top,
    output  reg[`Reg_Data_Bus] Output_Top=`Zero32,
    output  reg[0:0] Output_Top_Flag
);

    // reg [`Reg_Data_Bus] Output_Top_Reg = `Zero32;
    // assign Output_Top   

    //根据指令把数据送入ALU
    always @(*) begin
        Write_Reg_Addr_Output = Write_Reg_Addr;
        Write_Reg_Flag_Output = Write_Reg_Flag;

        ALU_Operation = `ALU_NOP;
        ALU_A_Output = `Zero32;
        ALU_B_Output = `Zero32;

        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
        Write_Reg_from_CU_Flag_Output = `Write_Reg_from_CU_Disabled;
        Write_Reg_from_CU_Data_Output = `Regs_Rst;

        RAM_Access_Flag_Output = `RAM_Access_Flag_Disabled;
        RAM_Operation_Output = `RAM_NOP;
        RAM_Write_Data_Output = `Zero32;

        Output_Top_Flag = `Output_Top_Disabled;
        case (opcode)

            //I型指令
            `INST_TYPE_I: begin
                case (func3)
                    `INST_ADDI: begin
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;

                    end


                    `INST_SLTI: begin
                        ALU_Operation = `ALU_Compare_Less_Set_1;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end


                    `INST_SLTIU: begin
                        ALU_Operation = `ALU_Unsign_Compare_Less_Set_1;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end
                    `INST_XORI: begin
                        ALU_Operation = `ALU_XOR;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end
                    `INST_ORI: begin
                        ALU_Operation = `ALU_OR;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end
                    `INST_ANDI: begin
                        ALU_Operation = `ALU_AND;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end
                    `INST_SLLI: begin
                        ALU_Operation = `ALU_Logical_Left_Shift;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {
                            {27{imm12[11]}}, Instruction_Input[24:20]
                        };

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end

                    `INST_SRLI_or_SRAI: begin
                        case (func7)
                            `INST_SRLI: begin
                                ALU_Operation = `ALU_Logical_Right_Shift;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = {
                                    {27{imm12[11]}}, Instruction_Input[24:20]
                                };

                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end

                            `INST_SRAI: begin
                                ALU_Operation = `ALU_Arithmetic_Right_Shift;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = {
                                    {27{imm12[11]}}, Instruction_Input[24:20]
                                };

                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end


                            default: begin

                            end
                        endcase

                    end


                    default begin
                        //执行NOP指令
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = `ALU_Rst_Data;
                        ALU_B_Output = `ALU_Rst_Data;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                    end
                endcase
            end


            //R型指令
            `INST_TYPE_R: begin
                case (func3)
                    `INST_ADD_or_SUB: begin
                        case (func7)
                            `INST_ADD: begin
                                ALU_Operation = `ALU_ADD;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = Reg_2_Read_Data_Input;
                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end
                            `INST_SUB: begin
                                ALU_Operation = `ALU_SUB;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = Reg_2_Read_Data_Input;
                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end



                            default begin
                                //执行NOP指令
                                ALU_Operation = `ALU_ADD;
                                ALU_A_Output = `ALU_Rst_Data;
                                ALU_B_Output = `ALU_Rst_Data;
                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                            end
                        endcase
                    end

                    `INST_SLL: begin
                        ALU_Operation = `ALU_Logical_Left_Shift;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end

                    `INST_SLT: begin
                        ALU_Operation = `ALU_Compare_Less_Set_1;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;

                    end

                    `INST_SLTU: begin
                        ALU_Operation = `ALU_Unsign_Compare_Less_Set_1;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;

                    end

                    `INST_XOR: begin
                        ALU_Operation = `ALU_XOR;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end


                    `INST_SRL_o_SRA: begin
                        case (func7)
                            `INST_SRL: begin
                                ALU_Operation = `ALU_Logical_Right_Shift;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = Reg_2_Read_Data_Input;
                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end
                            `INST_SRA: begin
                                ALU_Operation = `ALU_Arithmetic_Right_Shift;
                                ALU_A_Output = Reg_1_Read_Data_Input;
                                ALU_B_Output = Reg_2_Read_Data_Input;
                                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                            end
                        endcase
                    end

                    `INST_OR: begin
                        ALU_Operation = `ALU_OR;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end
                    `INST_AND: begin
                        ALU_Operation = `ALU_AND;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = Reg_2_Read_Data_Input;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end




                    default begin
                        //执行NOP指令
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = `ALU_Rst_Data;
                        ALU_B_Output = `ALU_Rst_Data;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                    end
                endcase
            end



            //S型指令
            `INST_TYPE_S: begin
                case (func3)
                    `INST_SB: begin
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {
                            {20{Instruction_Input[31]}},
                            {Instruction_Input[31:25]},
                            {Instruction_Input[11:7]}
                        };
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;

                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Write_Byte;
                        RAM_Write_Data_Output = {
                            {24{Reg_2_Read_Data_Input[7]}},
                            Reg_2_Read_Data_Input[7:0]
                        };
                    end
                    `INST_SH: begin
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {
                            {20{Instruction_Input[31]}},
                            {Instruction_Input[31:25]},
                            {Instruction_Input[11:7]}
                        };
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;

                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Write_Half_Word;
                        RAM_Write_Data_Output = {
                            {16{Reg_2_Read_Data_Input[15]}},
                            Reg_2_Read_Data_Input[15:0]
                        };
                    end
                    `INST_SW: begin
                        // ALU计算写入地址 = rs1值+imm7 扩展为32位  写入寄存器地址 = rs2值

                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {
                            {20{Instruction_Input[31]}},
                            {Instruction_Input[31:25]},
                            {Instruction_Input[11:7]}
                        };
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;

                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Write_Word;
                        RAM_Write_Data_Output = Reg_2_Read_Data_Input;
                    end

                endcase
            end



            `INST_TYPE_L: begin
                case (func3)
                    `INST_LB: begin
                        //读RAM地址 = rs1值+偏移地址       写入寄存器地址 = rd
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Read_Byte;
                        RAM_Write_Data_Output = `Zero32;
                    end
                    `INST_LH: begin
                        //读RAM地址 = rs1值+偏移地址       写入寄存器地址 = rd
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Read_Half_Word;
                        RAM_Write_Data_Output = `Zero32;
                    end

                    `INST_LW: begin
                        //读RAM地址 = rs1值+偏移地址       写入寄存器地址 = rd
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Read_Word;
                        RAM_Write_Data_Output = `Zero32;
                    end
                    `INST_LBU: begin
                        //读RAM地址 = rs1值+偏移地址       写入寄存器地址 = rd
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Read_Byte_Unsigned;
                        RAM_Write_Data_Output = `Zero32;
                    end
                    `INST_LHU: begin
                        //读RAM地址 = rs1值+偏移地址       写入寄存器地址 = rd
                        ALU_Operation = `ALU_ADD;
                        ALU_A_Output = Reg_1_Read_Data_Input;
                        ALU_B_Output = {{20{imm12[11]}}, imm12};

                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
                        RAM_Access_Flag_Output = `RAM_Access_Flag_Enabled;
                        RAM_Operation_Output = `RAM_Read_Half_Word_Unsigned;
                        RAM_Write_Data_Output = `Zero32;
                    end
                    default: begin

                    end
                endcase
            end



            `INST_JAL: begin
                ALU_Operation = `ALU_ADD;
                ALU_A_Output = {
                    {11{Instruction_Input[31]}},
                    Instruction_Input[31],
                    Instruction_Input[19:12],
                    Instruction_Input[20:20],
                    Instruction_Input[30:21],
                    {1'b0}
                };
                ALU_B_Output = Instruction_Addr_Input;

                Write_Reg_from_CU_Flag_Output = `Write_Reg_from_CU_Enabled;
                Write_Reg_from_CU_Data_Output = Instruction_Addr_Input + 32'b100;  //将下一条指令地址Instruction_Addr+4放入1寄存器rd中
            end

            `INST_JALR: begin
                ALU_Operation = `ALU_ADD;
                ALU_A_Output = Reg_1_Read_Data_Input;
                ALU_B_Output = {
                    {20{Instruction_Input[31]}}, Instruction_Input[31:20]
                };

                Write_Reg_from_CU_Flag_Output = `Write_Reg_from_CU_Enabled;
                Write_Reg_from_CU_Data_Output = Instruction_Addr_Input + 32'b100;  //将下一条指令地址Instruction_Addr+4放入1寄存器rd中
            end






            `INST_TYPE_B: begin
                case (func3)
                    `INST_BEQ: begin
                        //beq rs1 = rs2 时跳转
                        ALU_Operation = `ALU_SUB;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end
                    `INST_BNE: begin
                        //bne rs1 != rs2 时跳转
                        ALU_Operation = `ALU_SUB;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end
                    `INST_BLT: begin
                        // rs1 < rs2时跳转
                        ALU_Operation = `ALU_Compare_Less_Set_1;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end
                    `INST_BGE: begin
                        // rs1 >= rs2时跳转
                        ALU_Operation = `ALU_Compare_Less_Set_1;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end
                    `INST_BLTU: begin
                        ALU_Operation = `ALU_Unsign_Compare_Less_Set_1;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end
                    `INST_BGEU: begin
                        ALU_Operation = `ALU_Unsign_Compare_Less_Set_1;
                        ALU_A_Output  = Reg_1_Read_Data_Input;
                        ALU_B_Output  = Reg_2_Read_Data_Input;
                    end

                endcase
            end


            `INST_LUI: begin
                ALU_Operation = `ALU_Logical_Left_Shift;
                ALU_A_Output = imm20;
                ALU_B_Output = 32'b1100;

                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
            end

            `AUIPC: begin
                ALU_Operation = `ALU_ADD;
                ALU_A_Output = imm20 << 12;
                ALU_B_Output = Instruction_Addr_Input;
                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
            end



            `INST_ECALL: begin
                case (Reg_1_Read_Data_Input)
                    8'h3f: begin
                        $display("Read:%d", Reg_2_Read_Data_Input);
                        Output_Top = (rst == `Rst_Enabled ) ? 32'b10101010 : Reg_2_Read_Data_Input;
                    end

                    8'h40:begin
                        $display("Write:",Input_Top);
                        ALU_Operation = `ALU_Logical_Left_Shift;
                        ALU_A_Output = Input_Top;
                        ALU_B_Output = 0;
                        Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Enabled;
                    end


                endcase




            end


            default begin
                //执行NOP指令
                ALU_Operation = `ALU_ADD;
                ALU_A_Output = `ALU_Rst_Data;
                ALU_B_Output = `ALU_Rst_Data;
                Write_Reg_from_ALU_Flag_Output = `Write_reg_from_ALU_Disabled;
            end


        endcase
    end


    // 从ALU中取出计算结果继续执行
    always @(posedge clk) begin
        $display(
            $time,
            "          CU:  in => Inst:%d,Inst_Addr:%d,   opcode:%d,  imm12:%d, imm20:%d,  func3:%d,  func7:%d, Reg1:%d, Reg2:%d",
            Instruction_Input, Instruction_Addr_Input, opcode, imm12, imm20,
            func3, func7, $signed(Reg_1_Read_Data_Input), $signed(Reg_2_Read_Data_Input));
        $display($time, "          CU:  To ALU: op:%d,  A:%d,  B:%d  ",
                 ALU_Operation, $signed(ALU_A_Output), $signed(ALU_B_Output));
        $display($time,
                 "          CU:  To Regs: Write_Flag:%d,  Write_Addr:%d ",
                 Write_Reg_Flag_Output, Write_Reg_Addr_Output);
    end















endmodule
